#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pandas as pd
from pandas.core.frame import DataFrame
import numpy as np
import copy
import math #一些数学计算函数
import datetime#获取更毫秒级时间
import matplotlib.pyplot as plt#约定俗成的写法plt
import os
# 设置最大显示的行数：
pd.set_option('display.max_columns',1000)
pd.set_option('display.max_columns',None)
# 设置显示的宽度：
pd.set_option('display.width',1000)
# 设置显示的最大列宽，可以用于规范数据输出打印：
pd.set_option('display.max_colwidth',1000)
# 设置不用科学计数法显示：
# pd.set_option('display.float_format', lambda x: '%.3f' % x)

def chengzhijisuan(pzbz):
    '''
    返回乘值，需要品种代码如输入‘IC888’,返回ic888的乘值。
    '''
    zdt = ['IC888',	'IF888','IH888','T888',	'TF888','TS888','AP888','CF888','CY888','FG888','JR888','LR888','MA888','OI888','PM888','RI888','RM888','RS888','SF888','SM888','SR888','TA888','WH888','ZC888','A888',	'B888',	'BB888','C888',	'CS888','FB888','I888',	'J888','JD888',	'JM888','L888',	'M888',	'P888',	'PP888','V888',	'Y888',	'AG888','AL888','AU888','BU888','CU888','FU888','HC888','NI888','PB888','RB888','RU888','SC888','SN888','ZN888','SP888','EG888','CJ888','UR888','NR888','RR888','SS888','EB888',]
    zdcz = [300,	300,	200,	10000,	10000,	20000,	10,	5,	5,	20,	20,	20,	10,	10,	50,	20,	10,	10,	5,	5,	10,	5,	20,	100,	10,	10,	500,	10,	10,	500,	100,	100,	10,	60,	5,	10,	10,	5,	5,	10,	15,	5,	1000,	10,	5,	10,	10,	1,	5,	10,	10,	1000,	1,	5,	10,	10,	5,	20,	10,	10,	5,	5,]
    zdbzj = [0.01,	0.01,	0.1,	0.02,	0.015,	0.005,	0.11,	0.07,	0.05,	0.07,	0.05,	0.05,	0.07,	0.07,	0.1,	0.05,	0.06,	0.2,	0.07,	0.07,	0.05,	0.06,	0.2,	0.08,	0.07,	0.07,	0.2,	0.05,	0.05,	0.2,	0.08,	0.09,	0.08,	0.09,	0.07,	0.07,	0.06,	0.07,	0.07,	0.06,	0.06,	0.07,	0.05,	0.08,	0.07,	0.1,	0.08,	0.08,	0.08,	0.09,	0.09,	0.07,	0.07,	0.08,	0.07,	0.06,	0.07,	0.06,	0.09,	0.05,	0.7,	0.7,]
    zdzxbddw = [0.2,	0.2,	0.2,	0.005,	0.005,	0.005,	1,	5,	5,	1,	1,	1,	1,	1,	1,	1,	1,	1,	2,	2,	1,	2,	1,	0.2,	1,	1,	0.05,	1,	1,	0.05,	0.5,	0.5,	1,	0.5,	5,	1,	2,	1,	5,	2,	1,	5,	0.05,	2,	10,	1,	1,	10,	5,	1,	5,	0.1,	10,	5,	2,	1,	5,	1,	5,	1,	10,	1,]
    return zdcz[zdt.index(pzbz)]

def Loddata(sjlx):
    '''
    :param sjlx: 需要导入的数据类型，如收盘价和开盘价等。close为收盘价矩阵。
    :return: 输出为一个np二维矩阵.
    '''
    df = []
    if sjlx == 'close_5m':
        df = np.load(rb'E:\\Data\\5m\\close_5m.npy')  # 重本目录打开二进制文件
    if sjlx == 'open_5m':
        df = np.load(rb'E:\\Data\\5m\\open_5m.npy')  # 重本目录打开二进制文件
    if sjlx == 'high_5m':
        df = np.load(rb'E:\\Data\\5m\\high_5m.npy')  # 重本目录打开二进制文件
    if sjlx == 'low_5m':
        df = np.load(rb'E:\\Data\\5m\\low_5m.npy')  # 重本目录打开二进制文件
    if sjlx == 'volume_5m':
        df = np.load(rb'E:\\Data\\5m\\volume_5m.npy')  # 重本目录打开二进制文件
    if sjlx == 'oi_5m':
        df = np.load(rb'E:\\Data\\5m\\oi_5m.npy')  # 重本目录打开二进制文件

    if sjlx == 'close_10m':
        df = np.load(rb'E:\\Data\\10m\\close_10m.npy')  # 重本目录打开二进制文件
    if sjlx == 'open_10m':
        df = np.load(rb'E:\\Data\\10m\\open_10m.npy')  # 重本目录打开二进制文件
    if sjlx == 'high_10m':
        df = np.load(rb'E:\\Data\\10m\\high_10m.npy')  # 重本目录打开二进制文件
    if sjlx == 'low_10m':
        df = np.load(rb'E:\\Data\\10m\\low_10m.npy')  # 重本目录打开二进制文件
    if sjlx == 'volume_10m':
        df = np.load(rb'E:\\Data\\10m\\volume_10m.npy')  # 重本目录打开二进制文件
    if sjlx == 'oi_10m':
        df = np.load(rb'E:\\Data\\10m\\oi_10m.npy')  # 重本目录打开二进制文件

    if sjlx == 'close_15m':
        df = np.load(rb'E:\\Data\\15m\\close_15M.npy')  # 重本目录打开二进制文件
    if sjlx == 'open_15m':
        df = np.load(rb'E:\\Data\\15m\\open_15m.npy')  # 重本目录打开二进制文件
    if sjlx == 'high_15m':
        df = np.load(rb'E:\\Data\\15m\\high_15m.npy')  # 重本目录打开二进制文件
    if sjlx == 'low_15m':
        df = np.load(rb'E:\\Data\\15m\\low_15m.npy')  # 重本目录打开二进制文件
    if sjlx == 'volume_15m':
        df = np.load(rb'E:\\Data\\15m\\volume_15m.npy')  # 重本目录打开二进制文件
    if sjlx == 'oi_15m':
        df = np.load(rb'E:\\Data\\15m\\oi_15m.npy')  # 重本目录打开二进制文件

    if sjlx == 'close_30m':
        df = np.load(rb'E:\\Data\\30m\\close_30M.npy')  # 重本目录打开二进制文件
    if sjlx == 'open_30m':
        df = np.load(rb'E:\\Data\\30m\\open_30m.npy')  # 重本目录打开二进制文件
    if sjlx == 'high_30m':
        df = np.load(rb'E:\\Data\\30m\\high_30m.npy')  # 重本目录打开二进制文件
    if sjlx == 'low_30m':
        df = np.load(rb'E:\\Data\\30m\\low_30m.npy')  # 重本目录打开二进制文件
    if sjlx == 'volume_30m':
        df = np.load(rb'E:\\Data\\30m\\volume_30m.npy')  # 重本目录打开二进制文件
    if sjlx == 'oi_30m':
        df = np.load(rb'E:\\Data\\30m\\oi_30m.npy')  # 重本目录打开二进制文件

    if sjlx == 'close_60m':
        df = np.load(rb'E:\\Data\\60m\\close_60m.npy')  # 重本目录打开二进制文件
    if sjlx == 'open_60m':
        df = np.load(rb'E:\\Data\\60m\\open_60m.npy')  # 重本目录打开二进制文件
    if sjlx == 'high_60m':
        df = np.load(rb'E:\\Data\\60m\\high_60m.npy')  # 重本目录打开二进制文件
    if sjlx == 'low_60m':
        df = np.load(rb'E:\\Data\\60m\\low_60m.npy')  # 重本目录打开二进制文件
    if sjlx == 'volume_60m':
        df = np.load(rb'E:\\Data\\60m\\volume_60m.npy')  # 重本目录打开二进制文件
    if sjlx == 'oi_60m':
        df = np.load(rb'E:\\Data\\60m\\oi_60m.npy')  # 重本目录打开二进制文件

    if sjlx == 'close_120m':
        df = np.load(rb'E:\\Data\\120m\\close_120m.npy')  # 重本目录打开二进制文件
    if sjlx == 'open_120m':
        df = np.load(rb'E:\\Data\\120m\\open_120m.npy')  # 重本目录打开二进制文件
    if sjlx == 'high_120m':
        df = np.load(rb'E:\\Data\\120m\\high_120m.npy')  # 重本目录打开二进制文件
    if sjlx == 'low_120m':
        df = np.load(rb'E:\\Data\\120m\\low_120m.npy')  # 重本目录打开二进制文件
    if sjlx == 'volume_120m':
        df = np.load(rb'E:\\Data\\120m\\volume_120m.npy')  # 重本目录打开二进制文件
    if sjlx == 'oi_120m':
        df = np.load(rb'E:\\Data\\120m\\oi_120m.npy')  # 重本目录打开二进制文件

    if sjlx == 'close_180m':
        df = np.load(rb'E:\\Data\\180m\\close_180m.npy')  # 重本目录打开二进制文件
    if sjlx == 'open_180m':
        df = np.load(rb'E:\\Data\\180m\\open_180m.npy')  # 重本目录打开二进制文件
    if sjlx == 'high_180m':
        df = np.load(rb'E:\\Data\\180m\\high_180m.npy')  # 重本目录打开二进制文件
    if sjlx == 'low_180m':
        df = np.load(rb'E:\\Data\\180m\\low_180m.npy')  # 重本目录打开二进制文件
    if sjlx == 'volume_180m':
        df = np.load(rb'E:\\Data\\180m\\volume_180m.npy')  # 重本目录打开二进制文件
    if sjlx == 'oi_180m':
        df = np.load(rb'E:\\Data\\180m\\oi_180m.npy')  # 重本目录打开二进制文件

    if sjlx == 'close_240m':
        df = np.load(rb'E:\\Data\\240m\\close_240m.npy')  # 重本目录打开二进制文件
    if sjlx == 'open_240m':
        df = np.load(rb'E:\\Data\\240m\\open_240m.npy')  # 重本目录打开二进制文件
    if sjlx == 'high_240m':
        df = np.load(rb'E:\\Data\\240m\\high_240m.npy')  # 重本目录打开二进制文件
    if sjlx == 'low_240m':
        df = np.load(rb'E:\\Data\\240m\\low_240m.npy')  # 重本目录打开二进制文件
    if sjlx == 'volume_240m':
        df = np.load(rb'E:\\Data\\240m\\volume_240m.npy')  # 重本目录打开二进制文件
    if sjlx == 'oi_240m':
        df = np.load(rb'E:\\Data\\240m\\oi_240m.npy')  # 重本目录打开二进制文件

    if sjlx == 'close_1d':
        df = np.load(rb'E:\\Data\\1d\\close_1d.npy')  # 重本目录打开二进制文件
    if sjlx == 'open_1d':
        df = np.load(rb'E:\\Data\\1d\\open_1d.npy')  # 重本目录打开二进制文件
    if sjlx == 'high_1d':
        df = np.load(rb'E:\\Data\\1d\\high_1d.npy')  # 重本目录打开二进制文件
    if sjlx == 'low_1d':
        df = np.load(rb'E:\\Data\\1d\\low_1d.npy')  # 重本目录打开二进制文件
    if sjlx == 'volume_1d':
        df = np.load(rb'E:\\Data\\1d\\volume_1d.npy')  # 重本目录打开二进制文件
    if sjlx == 'oi_1d':
        df = np.load(rb'E:\\Data\\1d\\oi_1d.npy')  # 重本目录打开二进制文件

    return df


def Return(mat, n):
    '''
    求n日收益率，输入收盘价矩阵，返回对应收益率矩阵，
    '''
    ret = np.zeros(np.shape(mat))*np.nan
    for k in range(np.shape(mat)[1]):
        idx = np.isnan((mat[:, k])) == False
        temp = np.copy(mat[idx, k])
        rettemp = np.zeros(np.shape(temp))*np.nan
        for i in range(n, len(temp)):
            rettemp[i] = temp[i]/temp[i-n]-1
        ret[idx, k] = np.copy(rettemp)
    return ret

def ErWeiShuZuPaiXu(lsbl33):
    '''
    输入一个二维数组，输出排序后的数组。
    '''
    lsbl33 = np.argsort(lsbl33) #按升序排列
    lsbl44 = len(lsbl33)
    x = np.zeros(lsbl44) * np.nan #创建长度为lsbl44的二维数组
    x[lsbl33] = range(lsbl44) #将对应的序列填入对应排好的序列中
    return x

def MaxDrawdown(date,shouyi):
    '''
    最大回撤率,输入日期期加日累计收益率的矩阵，返回最大回撤值、回撤开始日期和回撤结束日期和收益回撤比。
    '''

    shouyi[shouyi == 0] = 0.0001
    # print(date)
    # print(shouyi)
    x = shouyi
    np.maximum.accumulate(x)
    j = np.argmax(np.maximum.accumulate(x) - x)
    # print('j is {j}'.format(j=j), shouyi[j, 0])
    huicejieshuriqi = date[j]
    i = np.argmax(x[:j])
    # print('i is {i}'.format(i=i), shouyi[i, 0])
    huiceqishiriqi = date[i]
    zuidahuice = round(x[i] - x[j], 2)
    ret2dd = round((x[-1]-x[0])/zuidahuice, 2)
    return zuidahuice, huiceqishiriqi, huicejieshuriqi, ret2dd

def XiaPu(shouyi):
    '''
    计算夏普比率,输入日期期加日累计收益率的矩阵，返回夏普值。
    '''
    # 计算超额回报率
    ex_pct_close =shouyi.mean() * 250-0.04
    xiapu = np.round(ex_pct_close / math.sqrt(250)/shouyi.std(), 2)

    return xiapu
def HuiCe6(ysj, zhouqi, kaishixuhao):
    '''
    作用：对条件判断正反手策略进行进行回测，传入的回测矩阵为1或者-1,1为开多，-1为开空，仓位为等权分配。
    输入参数1：因子矩阵，参数2：回测周期，如:5为5分钟，240为4小时，480为日线。参数3：开始回测时间对应的序号。
    返回：每年和整体盈亏指标。
    '''
    chushishouyi = []
    datetime = []
    if zhouqi == 5:
        chushishouyi = np.load('E:\\Testdata\\5m\\shouyi_5m.npy', allow_pickle=True)
        datetime = np.load('E:\\Testdata\\5m\\datetime_5m.npy', allow_pickle=True)
        # print(len(datetime[:,0]))
    if zhouqi == 10:
        chushishouyi = np.load('E:\\Testdata\\10m\\shouyi_10m.npy', allow_pickle=True)
        datetime = np.load('E:\\Testdata\\10m\\datetime_10m.npy', allow_pickle=True)
    if zhouqi == 15:
        chushishouyi = np.load('E:\\Testdata\\15m\\shouyi_15m.npy', allow_pickle=True)
        datetime = np.load('E:\\Testdata\\15m\\datetime_15m.npy', allow_pickle=True)
    if zhouqi == 30:
        chushishouyi = np.load('E:\\Testdata\\30m\\shouyi_30m.npy', allow_pickle=True)
        datetime = np.load('E:\\Testdata\\30m\\datetime_30m.npy', allow_pickle=True)
    if zhouqi == 60:
        chushishouyi = np.load('E:\\Testdata\\60m\\shouyi_60m.npy', allow_pickle=True)
        datetime = np.load('E:\\Testdata\\60m\\datetime_60m.npy', allow_pickle=True)
    if zhouqi == 120:
        chushishouyi = np.load('E:\\Testdata\\120m\\shouyi_120m.npy', allow_pickle=True)
        datetime = np.load('E:\\Testdata\\120m\\datetime_120m.npy', allow_pickle=True)
    if zhouqi == 180:
        chushishouyi = np.load('E:\\Testdata\\180m\\shouyi_180m.npy', allow_pickle=True)
        datetime = np.load('E:\\Testdata\\180m\\datetime_180m.npy', allow_pickle=True)
    if zhouqi == 240:
        chushishouyi = np.load('E:\\Testdata\\240m\\shouyi_240m.npy', allow_pickle=True)
        datetime = np.load('E:\\Testdata\\240m\\datetime_240m.npy', allow_pickle=True)
    if zhouqi == 480:
        chushishouyi = np.load('E:\\Testdata\\1d\\shouyi_1d.npy', allow_pickle=True)
        datetime = np.load('E:\\Testdata\\1d\\datetime_1d.npy', allow_pickle=True)

    datetime = datetime[kaishixuhao:]
    chushishouyi = chushishouyi[kaishixuhao:]

    zongzhijin = 10000000#测试总资金
    yihangchangdu = len(ysj[0])
    lsbl22 = 1
    leijilirun = 0#累计利润初始值
    meirishouyi = []
    meirileijishouyi = []
    meirishouyirq = []
    j = -3
    meinianshouyi = []#每年收益
    meinianshouyirq = []#每年收益对应的日期
    j1 = -3
    j2=0
    shouyi = []#最终收益列表
    zuoduocangwei = []#做多仓位列表
    zuokongcangwei = []#做空仓位列表
    long = []#日均做多仓位
    short = []#日均做空仓位
    tvr = []#换手率
    zq_tvr = []#周期换手率
    meirihuanshoulv = []#每日换手率
    sh = []#夏普
    ret2dd = []#收益回撤比
    dd = []#最大回撤
    dd_start = []
    dd_end = []#最大回撤结束时间
    lsbl44 = -3
    lsbl10 = 0
    niankaishiriqi = []#年开始日期
    mg_bp = []#盈利能力

    dy = len(ysj[:, 0])#列总长度
    # dx = 1/len(ysj[1])#根据行总长度换算后的每个品种仓位
    anasb = np.isnan(ysj)#-----------
    cangweibeifengbi = 0
    cangweibeifengbi4 = np.zeros(np.shape(ysj))*np.nan
    zqhsl = 0
    i = 3
    while i < dy:
        x1 = anasb[i-1]#i-1是为了dell-1
        x = ysj[i-1]
        x3 = anasb[i-2]
        x4 = ysj[i-2]
        x5 = anasb[i-3]
        x6 = ysj[i-3]
        syh = chushishouyi[i]
        k = np.where(x1==True)  # 当前一行nan的位置
        k1 = np.where(x1==False)  # 当前一行不是nan的位置
        k3 = np.where(x3==True)  # 前面一行nan的位置
        k5 = np.where(x5==True)  # 前面二行nan的位置
        x4 = np.delete(x4, k3[0])  # 前面一行删除nan后的
        x6 = np.delete(x6, k5[0])  # 前面二行删除nan后的
        syh = np.delete(syh, k[0]) # 删除收益率的nan
        x = np.delete(x, k[0])  # 当前一行删除nan后的
        if len(x) > len(x4) and len(x4) <= len(x6):
            lsbl22 = 1#仓位控制
            # print('+++++++++++++++++++++++++++', datetime[i-1, 1], lsbl22, len(cangweibeifengbi4), cangweibeifengbi4)

        if len(x) < len(x4) and len(x4) >= len(x6):
            k2 = np.where(x3==False)  # 前面一行不是nan的位置
            syhwz = np.zeros(yihangchangdu) * np.nan
            syhwz[k2[0]] = cangweibeifengbi[range(len(k2[0]))]  # 将对应数组中的值填入对应位置
            syhwz = np.delete(syhwz, k1[0])  # 留下前面一行多余的位置，也就是找到无夜盘的品种
            syhwz[np.isnan(syhwz)] = 0
            lsbl22 = 1-sum(abs(syhwz))
            # print('-------------------------------', datetime[i-1, 1], x[0], lsbl22)

        if len(x) != 0:
            # dxx = lsbl22/len(x)  # 仓位分配计算
            # df = lsbl22/dxx*x  # 仓位百分比的计算
            cangweibeifengbi = x/sum(abs(x))  # 仓位多空分配
            # print('测试用显示==', sum(abs(cangweibeifengbi)))
            #z周期换手率计算
            cangweibeifengbi4[i, k1[0]] = cangweibeifengbi[range(len(k1[0]))]
            if len(x) <= len(x4):
                lsbl12 = np.delete(cangweibeifengbi4[i - 1:i], k[0])
                lsbl13 = np.delete(cangweibeifengbi4[i-2:i-1], k[0])
                # cangweibeifengbi2 = np.delete(cangweibeifengbi4[i - 1:i], k3[0])
            else:
                lsbl12 = np.delete(cangweibeifengbi4[i - 1:i], k3[0])
                lsbl13 = np.delete(cangweibeifengbi4[i - 2:i-1], k3[0])
                # cangweibeifengbi2 = np.delete(cangweibeifengbi4[i - 1:i], k[0])
            # cangweibeifengbi5 = pd.DataFrame(cangweibeifengbi4[i-2:i])#获得仓位的最后两行
            # lsbl12 = cangweibeifengbi5.dropna(axis=1, )#删除带nan的列
            # print(sum(abs(lsbl12-lsbl13)))
            zqhsl = sum(abs(lsbl12-lsbl13))  # 每周期的换手
            # print('测试专用4==', zq_tvr)
            #多空持仓率计算
            cangweibeifengbi2 = np.copy(cangweibeifengbi)  # 将仓位表复制
            cangweibeifengbi3 = np.copy(cangweibeifengbi2)
            cangweibeifengbi2[cangweibeifengbi2 < 0] = 0  # 将空仓为置为0，以便计算多仓的和
            zuoduocangwei.append(np.sum(cangweibeifengbi2))  # 计算多仓的和并保存值
            cangweibeifengbi3[cangweibeifengbi3 > 0] = 0
            zuokongcangwei.append(np.sum(cangweibeifengbi3))
            # print('专门测试用==', sum(abs(cangweibeifengbi)), np.sum(cangweibeifengbi2), np.sum(cangweibeifengbi3))
        df = (cangweibeifengbi * syh) * 100  # 仓位归一化后乘以收益率,获得最终开仓的资金(乘以了100)
        zq_tvr.append(zqhsl)
        df[np.isnan(df)] = 0  # 将受益列为nan的改为0-？？？求偏度后此位置有nan
        shouyi.append(sum(df))#每周期收益和
        lsbl10 += 1  # 收益回撤比用
        if zhouqi < 480:#判断是否是日线周期，日线周期的的累计利润计算方式不同
            j += 1
            if datetime[i, 0] != datetime[i-1, 0]:#日收益计算
                meirishouyirq.append(datetime[i-1, 0])
                # print(datetime[i-1, 1])
                lsbl11 = sum(shouyi[i-j-3:-1])
                # print(shouyi[i-j-3:-1])
                meirishouyi.append(lsbl11)
                leijilirun = leijilirun+lsbl11
                meirileijishouyi.append(leijilirun)
                lsbl14 = np.array(zq_tvr[i - j - 3:-1])
                lsbl14[np.isnan(lsbl14)] = 0  # 将nan替换为0
                meirihuanshoulv.append(sum(lsbl14))
                # print(sum(shouyi[i-j-3:-1]))
                j2 += 1
                lsbl44 += 1
                j = 0

        else:
            meirishouyirq.append(datetime[i, 0])
            lsbl11 = sum(df) # 每周期收益和
            leijilirun = leijilirun + lsbl11
            meirishouyi.append(lsbl11)
            meirileijishouyi.append(leijilirun)
            meirihuanshoulv.append(zqhsl)
            lsbl44 += 1
            # print(datetime[i])

        # 每年收益计算---------------------
        j1 += 1
        if datetime[i, 0][:4] != datetime[i - 1, 0][:4]:
            meinianshouyirq.append(datetime[i-1, 0])
            niankaishiriqi.append(datetime[i - j1, 0])
            meinianshouyi.append(sum(shouyi[i - j1 - 3:-1]))
            # print('专门测试用==', shouyi[i - j1 - 3:-1])
            lsbl15 = np.array(zuoduocangwei[i - j1 - 3:-1])
            lsbl15[np.isnan(lsbl15)] = 0  # 将nan替换为0
            lsbl55 = sum(lsbl15)/lsbl10
            lsbl15 = np.array(zuokongcangwei[i - j1 - 3:-1])
            lsbl15[np.isnan(lsbl15)] = 0  # 将nan替换为0
            lsbl66 = sum(lsbl15) / lsbl10
            lsbl77 = meirishouyirq[j2 - lsbl44-1:-1]
            lsbl88 = meirileijishouyi[j2 - lsbl44-1:-1]
            lsbl99 = meirishouyi[j2 - lsbl44-1:-1]
            long.append(lsbl55)
            short.append(lsbl66)
            lsbl14 = np.array(meirihuanshoulv[j2 - lsbl44-1:-1])
            lsbl14[np.isnan(lsbl14)] = 0  # 将nan替换为0
            nianjunhuanshoulv = sum(lsbl14) / lsbl44 * 100
            tvr.append(nianjunhuanshoulv)
            sh.append(XiaPu(np.array(lsbl99)))
            dd77, dd_start77, dd_end77, ret2dd77 = MaxDrawdown(lsbl77, np.array(lsbl88))
            dd.append(dd77)
            dd_start.append(dd_start77)
            dd_end.append(dd_end77)
            ret2dd.append(ret2dd77)
            mg_bp.append(meinianshouyi[-1]/nianjunhuanshoulv/lsbl44*10000)
            # print(lsbl44)#每日计数
            lsbl10 = 0#每周期计数清零
            lsbl44 = 0
            j1 = 0
            print('年化指标=', niankaishiriqi[-1],meinianshouyirq[-1], '夏普', sh[-1], '最大回撤', dd[-1], '换手率', tvr[-1] )#每年计算完后临时输出一些指标
        i += 1  # 主循环计算完成

    if zhouqi < 480:#判断是否是日线周期，日线周期的的累计利润计算方式不同
        # 循环完后最后一次或最后一天累计收益和每年收益计算
        meirishouyirq.append(datetime[i - 1, 0])
        lsbl11 = sum(shouyi[i - j - 3:-1])
        meirishouyi.append(lsbl11)
        leijilirun = leijilirun + lsbl11
        meirileijishouyi.append(leijilirun)
        lsbl14 = np.array(zq_tvr[i - j - 3:-1])
        lsbl14[np.isnan(lsbl14)] = 0  # 将nan替换为0
        meirihuanshoulv.append(sum(lsbl14))
        lsbl44 += 1

    # 循环完后最后一次或最后一天累计收益和每年收益计算
    meinianshouyirq.append(datetime[i - 1, 0]) # 每年开始日期
    niankaishiriqi.append(datetime[i - j1, 0])
    meinianshouyi.append(sum(shouyi[i - j1 - 3:]))
    lsbl15 = np.array(zuoduocangwei[i - j1 - 3:-1])
    lsbl15[np.isnan(lsbl15)] = 0  # 将nan替换为0
    lsbl55 = sum(lsbl15) / lsbl10
    lsbl15 = np.array(zuokongcangwei[i - j1 - 3:-1])
    lsbl15[np.isnan(lsbl15)] = 0  # 将nan替换为0
    lsbl66 = sum(lsbl15) / lsbl10
    lsbl77 = meirishouyirq[j2 - lsbl44:-1]
    lsbl88 = meirileijishouyi[j2 - lsbl44:-1]
    lsbl99 = meirishouyi[j2 - lsbl44:-1]
    long.append(lsbl55)
    short.append(lsbl66)
    lsbl14 = np.array(meirihuanshoulv[j2 - lsbl44 - 1:-1])
    lsbl14[np.isnan(lsbl14)] = 0  # 将nan替换为0
    nianjunhuanshoulv = sum(lsbl14) / lsbl44 * 100
    tvr.append(nianjunhuanshoulv)

    # print('测试专用4==', sum(lsbl14), lsbl10)
    sh.append(XiaPu(np.array(lsbl99)))
    dd77, dd_start77, dd_end77, ret2dd77 = MaxDrawdown(lsbl77, np.array(lsbl88))
    dd.append(dd77)
    dd_start.append(dd_start77)
    dd_end.append(dd_end77)
    ret2dd.append(ret2dd77)
    mg_bp.append(meinianshouyi[-1] / nianjunhuanshoulv/lsbl44*10000)
    print('年化指标=', niankaishiriqi[-1],meinianshouyirq[-1], '夏普', sh[-1], '最大回撤', dd[-1], '换手率', tvr[-1])  # 每年计算完后临时输出一些指标

    #就合计平均
    year = []
    for i6 in niankaishiriqi:
        year.append(i6[:4])
    niankaishiriqi.append(niankaishiriqi[0])
    meinianshouyirq.append(meinianshouyirq[-1])
    long.append(np.mean(long))
    short.append(np.mean(short))
    meinianshouyi.append(np.mean(meinianshouyi))
    tvr.append(np.mean(tvr))
    sh.append(np.mean(sh))
    dd77, dd_start77, dd_end77, ret2dd77 = MaxDrawdown(meirishouyirq, np.array(meirileijishouyi))
    ret2dd.append(ret2dd77)
    dd.append(dd77)
    dd_start.append(dd_start77)
    dd_end.append(dd_end77)
    mg_bp.append(np.mean(mg_bp)/250*100)
    year.append('all')

    #计算整个曲线的指标
    year.append('Profit')
    niankaishiriqi.append(niankaishiriqi[0])
    meinianshouyirq.append(meinianshouyirq[-1])
    lsbl15 = np.array(zuoduocangwei)
    lsbl15[np.isnan(lsbl15)] = 0  # 将nan替换为0
    long.append(np.mean(lsbl15))
    lsbl15 = np.array(zuokongcangwei)
    lsbl15[np.isnan(lsbl15)] = 0  # 将nan替换为0
    short.append(np.mean(lsbl15))
    meinianshouyi.append(meirileijishouyi[-1])
    tvr.append(np.mean(tvr[-1]))
    sh.append(XiaPu(np.array(meirishouyi)))#

    ret2dd.append(ret2dd77)
    dd.append(dd77)
    dd_start.append(dd_start77)
    dd_end.append(dd_end77)
    mg_bp.append(mg_bp[-1])


    reg = {"year": year, "from": niankaishiriqi, "to": meinianshouyirq, "long": np.round(long,2), "short": np.round(short,2), "ret": np.round(meinianshouyi,2),
           "tvr": np.round(tvr, 2), "sh": np.round(sh, 2), "ret2dd": ret2dd, "dd": dd, "dd_start": dd_start, "dd_end": dd_end, "mg_bp": np.round(mg_bp, 2)}#将列表a，b转换成字典
    reg = DataFrame(reg)

    rileijishouyi = {"date": meirishouyirq, "ret": meirileijishouyi}
    rileijishouyi = DataFrame(rileijishouyi)
    print('-----------------------------------------------------综合指标----------------------------------------------------')
    print(reg)
    return reg, rileijishouyi

def HuiCe(ysj, zhouqi, kaishixuhao):
    '''
    作用：对因子进行回测。
    输入参数1：因子矩阵，参数2：回测周期，如:5为5分钟，240为4小时，480为日线。参数3：开始回测时间对应的序号。
    返回：每年和整体盈亏指标。
    '''
    chushishouyi = []
    datetime = []
    if zhouqi == 5:
        chushishouyi = np.load('E:\\Testdata\\5m\\shouyi_5m.npy', allow_pickle=True)
        datetime = np.load('E:\\Testdata\\5m\\datetime_5m.npy', allow_pickle=True)
        # print(len(datetime[:,0]))
    if zhouqi == 10:
        chushishouyi = np.load('E:\\Testdata\\10m\\shouyi_10m.npy', allow_pickle=True)
        datetime = np.load('E:\\Testdata\\10m\\datetime_10m.npy', allow_pickle=True)
    if zhouqi == 15:
        chushishouyi = np.load('E:\\Testdata\\15m\\shouyi_15m.npy', allow_pickle=True)
        datetime = np.load('E:\\Testdata\\15m\\datetime_15m.npy', allow_pickle=True)
    if zhouqi == 30:
        chushishouyi = np.load('E:\\Testdata\\30m\\shouyi_30m.npy', allow_pickle=True)
        datetime = np.load('E:\\Testdata\\30m\\datetime_30m.npy', allow_pickle=True)
    if zhouqi == 60:
        chushishouyi = np.load('E:\\Testdata\\60m\\shouyi_60m.npy', allow_pickle=True)
        datetime = np.load('E:\\Testdata\\60m\\datetime_60m.npy', allow_pickle=True)
    if zhouqi == 120:
        chushishouyi = np.load('E:\\Testdata\\120m\\shouyi_120m.npy', allow_pickle=True)
        datetime = np.load('E:\\Testdata\\120m\\datetime_120m.npy', allow_pickle=True)
    if zhouqi == 180:
        chushishouyi = np.load('E:\\Testdata\\180m\\shouyi_180m.npy', allow_pickle=True)
        datetime = np.load('E:\\Testdata\\180m\\datetime_180m.npy', allow_pickle=True)
    if zhouqi == 240:
        chushishouyi = np.load('E:\\Testdata\\240m\\shouyi_240m.npy', allow_pickle=True)
        datetime = np.load('E:\\Testdata\\240m\\datetime_240m.npy', allow_pickle=True)
    if zhouqi == 480:
        chushishouyi = np.load('E:\\Testdata\\1d\\shouyi_1d.npy', allow_pickle=True)
        datetime = np.load('E:\\Testdata\\1d\\datetime_1d.npy', allow_pickle=True)

    datetime = datetime[kaishixuhao:]
    chushishouyi = chushishouyi[kaishixuhao:]

    zongzhijin = 10000000#测试总资金
    yihangchangdu = len(ysj[0])
    lsbl22 = 1
    leijilirun = 0#累计利润初始值
    meirishouyi = []
    meirileijishouyi = []
    meirishouyirq = []
    j = -3
    meinianshouyi = []#每年收益
    meinianshouyirq = []#每年收益对应的日期
    j1 = -3
    j2=0
    shouyi = []#最终收益列表
    zuoduocangwei = []#做多仓位列表
    zuokongcangwei = []#做空仓位列表
    long = []#日均做多仓位
    short = []#日均做空仓位
    tvr = []#换手率
    zq_tvr = []#周期换手率
    meirihuanshoulv = []#每日换手率
    sh = []#夏普
    ret2dd = []#收益回撤比
    dd = []#最大回撤
    dd_start = []
    dd_end = []#最大回撤结束时间
    lsbl44 = -3
    lsbl10 = 0
    niankaishiriqi = []#年开始日期
    mg_bp = []#盈利能力

    dy = len(ysj[:, 0])
    anasb = np.isnan(ysj)#-----------
    cangweibeifengbi4 = np.zeros(np.shape(ysj))*np.nan
    zqhsl = 0.5
    i = 3
    while i < dy:
        x1 = anasb[i-1]#i-1是为了dell-1
        x = ysj[i-1]
        x3 = anasb[i-2]
        x4 = ysj[i-2]
        x5 = anasb[i-3]
        x6 = ysj[i-3]
        syh = chushishouyi[i]
        k = np.where(x1==True)  # 当前一行nan的位置
        k1 = np.where(x1==False)  # 当前一行不是nan的位置
        k3 = np.where(x3==True)  # 前面一行nan的位置
        k5 = np.where(x5==True)  # 前面二行nan的位置
        x4 = np.delete(x4, k3[0])  # 前面一行删除nan后的
        x6 = np.delete(x6, k5[0])  # 前面二行删除nan后的
        syh = np.delete(syh, k[0]) # 删除收益率的nan
        x = np.delete(x, k[0])  # 当前一行删除nan后的
        if len(x) > len(x4) and len(x4) <= len(x6):
            lsbl22 = 1#仓位控制
            # print('+++++++++++++++++++++++++++', datetime[i-1, 1], lsbl22, len(cangweibeifengbi4), cangweibeifengbi4)

        if len(x) < len(x4) and len(x4) >= len(x6):
            k2 = np.where(x3==False)  # 前面一行不是nan的位置
            syhwz = np.zeros(yihangchangdu) * np.nan
            syhwz[k2[0]] = cangweibeifengbi[range(len(k2[0]))]  # 将对应数组中的值填入对应位置
            syhwz = np.delete(syhwz, k1[0])  # 留下前面一行多余的位置，也就是找到无夜盘的品种
            syhwz[np.isnan(syhwz)] = 0
            lsbl22 = 1-sum(abs(syhwz))
            # print('-------------------------------', datetime[i-1, 1], x[0], lsbl22)

        df1 = ErWeiShuZuPaiXu(x)  # 默认的输出每行元素的排序值。这些索引值对应的元素是从小到大排序的
        dxx = len(x)
        # df = (df1 - dxx / 2) / (dxx * 2)  # 排序后的仓位
        df = ((df1 - ((dxx - 1) / 2)) / (dxx - 1)) * 2  # 仓位百分比的计算

        cangweibeifengbi = df*lsbl22 / sum(abs(df))  # 归一化后的仓位
        lsbl10 += 1#收益回撤比用
        #z周期换手率计算
        cangweibeifengbi4[i, k1[0]] = cangweibeifengbi[range(len(k1[0]))]
        if len(x) <= len(x4):
            lsbl12 = np.delete(cangweibeifengbi4[i - 1:i], k[0])
            lsbl13 = np.delete(cangweibeifengbi4[i-2:i-1], k[0])
        else:
            lsbl12 = np.delete(cangweibeifengbi4[i - 1:i], k3[0])
            lsbl13 = np.delete(cangweibeifengbi4[i - 2:i-1], k3[0])
        # cangweibeifengbi5 = pd.DataFrame(cangweibeifengbi4[i-2:i])#获得仓位的最后两行
        # lsbl12 = cangweibeifengbi5.dropna(axis=1, )#删除带nan的列
        zqhsl = sum(abs(lsbl12-lsbl13))  # 每周期的换手
        zq_tvr.append(zqhsl)
        # print('测试专用4==', zq_tvr)

        #多空持仓率计算
        cangweibeifengbi2 = np.copy(cangweibeifengbi)  # 将仓位表复制
        cangweibeifengbi3 = np.copy(cangweibeifengbi)
        cangweibeifengbi2[cangweibeifengbi2 < 0] = 0  # 将空仓为置为0，以便计算多仓的和
        zuoduocangwei.append(np.sum(cangweibeifengbi2))  # 计算多仓的和并保存值
        cangweibeifengbi3[cangweibeifengbi3 > 0] = 0
        zuokongcangwei.append(np.sum(cangweibeifengbi3))
        # print('专门测试用==', sum(abs(cangweibeifengbi)), np.sum(cangweibeifengbi2), np.sum(cangweibeifengbi3))
        df = (cangweibeifengbi * syh) * 100  # 仓位归一化后乘以收益率,获得最终开仓的资金(乘以了100)
        df[np.isnan(df)] = 0  # 将受益列为nan的改为0-？？？求偏度后此位置有nan
        shouyi.append(sum(df))#每周期收益和
        if zhouqi < 480:#判断是否是日线周期，日线周期的的累计利润计算方式不同
            j += 1
            if datetime[i, 0] != datetime[i-1, 0]:#日收益计算
                meirishouyirq.append(datetime[i-1, 0])
                # print(datetime[i-1, 1])
                lsbl11 = sum(shouyi[i-j-3:-1])
                # print(shouyi[i-j-3:-1])
                meirishouyi.append(lsbl11)
                leijilirun = leijilirun+lsbl11
                meirileijishouyi.append(leijilirun)
                lsbl14 = np.array(zq_tvr[i - j - 3:-1])
                lsbl14[np.isnan(lsbl14)] = 0  # 将nan替换为0
                meirihuanshoulv.append(sum(lsbl14))
                # print(sum(shouyi[i-j-3:-1]))
                j2 += 1
                lsbl44 += 1
                j = 0

        else:
            meirishouyirq.append(datetime[i, 0])
            lsbl11 = sum(df) # 每周期收益和
            leijilirun = leijilirun + lsbl11
            meirishouyi.append(lsbl11)
            meirileijishouyi.append(leijilirun)
            meirihuanshoulv.append(zqhsl)
            lsbl44 += 1
            # print(datetime[i])

        # 每年收益计算---------------------
        j1 += 1
        if datetime[i, 0][:4] != datetime[i - 1, 0][:4]:
            meinianshouyirq.append(datetime[i-1, 0])
            niankaishiriqi.append(datetime[i - j1, 0])
            meinianshouyi.append(sum(shouyi[i - j1 - 3:-1]))
            # print('专门测试用==', shouyi[i - j1 - 3:-1])
            lsbl15 = np.array(zuoduocangwei[i - j1 - 3:-1])
            lsbl15[np.isnan(lsbl15)] = 0  # 将nan替换为0
            lsbl55 = sum(lsbl15) / lsbl10
            lsbl15 = np.array(zuokongcangwei[i - j1 - 3:-1])
            lsbl15[np.isnan(lsbl15)] = 0  # 将nan替换为0
            lsbl66 = sum(lsbl15) / lsbl10

            lsbl77 = meirishouyirq[j2 - lsbl44-1:-1]
            lsbl88 = meirileijishouyi[j2 - lsbl44-1:-1]
            lsbl99 = meirishouyi[j2 - lsbl44-1:-1]
            long.append(lsbl55)
            short.append(lsbl66)
            lsbl14 = np.array(meirihuanshoulv[j2 - lsbl44-1:-1])
            lsbl14[np.isnan(lsbl14)] = 0  # 将nan替换为0
            nianjunhuanshoulv = sum(lsbl14) / lsbl44 * 100
            tvr.append(nianjunhuanshoulv)
            sh.append(XiaPu(np.array(lsbl99)))
            dd77, dd_start77, dd_end77, ret2dd77 = MaxDrawdown(lsbl77, np.array(lsbl88))
            dd.append(dd77)
            dd_start.append(dd_start77)
            dd_end.append(dd_end77)
            ret2dd.append(ret2dd77)
            mg_bp.append(meinianshouyi[-1]/nianjunhuanshoulv/lsbl44*10000)
            # print(lsbl44)#每日计数
            lsbl10 = 0#每周期计数清零
            lsbl44 = 0
            j1 = 0
            print('年化指标=', niankaishiriqi[-1],meinianshouyirq[-1], '夏普', sh[-1], '最大回撤', dd[-1], '换手率', tvr[-1] )#每年计算完后临时输出一些指标
        i += 1  # 主循环计算完成

    if zhouqi < 480:#判断是否是日线周期，日线周期的的累计利润计算方式不同
        # 循环完后最后一次或最后一天累计收益和每年收益计算
        meirishouyirq.append(datetime[i - 1, 0])
        lsbl11 = sum(shouyi[i - j - 3:-1])
        meirishouyi.append(lsbl11)
        leijilirun = leijilirun + lsbl11
        meirileijishouyi.append(leijilirun)
        lsbl14 = np.array(zq_tvr[i - j - 3:-1])
        lsbl14[np.isnan(lsbl14)] = 0  # 将nan替换为0
        meirihuanshoulv.append(sum(lsbl14))
        lsbl44 += 1

    # 循环完后最后一次或最后一天累计收益和每年收益计算
    meinianshouyirq.append(datetime[i - 1, 0]) # 每年开始日期
    niankaishiriqi.append(datetime[i - j1, 0])
    meinianshouyi.append(sum(shouyi[i - j1 - 3:]))
    lsbl15 = np.array(zuoduocangwei[i - j1 - 3:-1])
    lsbl15[np.isnan(lsbl15)] = 0  # 将nan替换为0
    lsbl55 = sum(lsbl15) / lsbl10
    lsbl15 = np.array(zuokongcangwei[i - j1 - 3:-1])
    lsbl15[np.isnan(lsbl15)] = 0  # 将nan替换为0
    lsbl66 = sum(lsbl15) / lsbl10

    lsbl77 = meirishouyirq[j2 - lsbl44:-1]
    lsbl88 = meirileijishouyi[j2 - lsbl44:-1]
    lsbl99 = meirishouyi[j2 - lsbl44:-1]
    long.append(lsbl55)
    short.append(lsbl66)
    lsbl14 = np.array(meirihuanshoulv[j2 - lsbl44 - 1:-1])
    lsbl14[np.isnan(lsbl14)] = 0  # 将nan替换为0
    nianjunhuanshoulv = sum(lsbl14) / lsbl44 * 100
    tvr.append(nianjunhuanshoulv)

    # print('测试专用4==', sum(lsbl14), lsbl10)
    sh.append(XiaPu(np.array(lsbl99)))
    dd77, dd_start77, dd_end77, ret2dd77 = MaxDrawdown(lsbl77, np.array(lsbl88))
    dd.append(dd77)
    dd_start.append(dd_start77)
    dd_end.append(dd_end77)
    ret2dd.append(ret2dd77)
    mg_bp.append(meinianshouyi[-1] / nianjunhuanshoulv/lsbl44*10000)
    print('年化指标=', niankaishiriqi[-1],meinianshouyirq[-1], '夏普', sh[-1], '最大回撤', dd[-1], '换手率', tvr[-1])  # 每年计算完后临时输出一些指标

    #就合计平均
    year = []
    for i6 in niankaishiriqi:
        year.append(i6[:4])
    niankaishiriqi.append(niankaishiriqi[0])
    meinianshouyirq.append(meinianshouyirq[-1])
    long.append(np.mean(long))
    short.append(np.mean(short))
    meinianshouyi.append(np.mean(meinianshouyi))
    tvr.append(np.mean(tvr))
    sh.append(np.mean(sh))
    dd77, dd_start77, dd_end77, ret2dd77 = MaxDrawdown(meirishouyirq, np.array(meirileijishouyi))
    ret2dd.append(ret2dd77)
    dd.append(dd77)
    dd_start.append(dd_start77)
    dd_end.append(dd_end77)
    mg_bp.append(np.mean(mg_bp)/250*100)
    year.append('all')

    #计算整个曲线的指标
    year.append('Profit')
    niankaishiriqi.append(niankaishiriqi[0])
    meinianshouyirq.append(meinianshouyirq[-1])
    lsbl15 = np.array(zuoduocangwei)
    lsbl15[np.isnan(lsbl15)] = 0  # 将nan替换为0
    long.append(np.mean(lsbl15))
    lsbl15 = np.array(zuokongcangwei)
    lsbl15[np.isnan(lsbl15)] = 0  # 将nan替换为0
    short.append(np.mean(lsbl15))
    meinianshouyi.append(meirileijishouyi[-1])
    tvr.append(np.mean(tvr[-1]))
    sh.append(XiaPu(np.array(meirishouyi)))#

    ret2dd.append(ret2dd77)
    dd.append(dd77)
    dd_start.append(dd_start77)
    dd_end.append(dd_end77)
    mg_bp.append(mg_bp[-1])


    reg = {"year": year, "from": niankaishiriqi, "to": meinianshouyirq, "long": np.round(long,2), "short": np.round(short,2), "ret": np.round(meinianshouyi,2),
           "tvr": np.round(tvr, 2), "sh": np.round(sh, 2), "ret2dd": ret2dd, "dd": dd, "dd_start": dd_start, "dd_end": dd_end, "mg_bp": np.round(mg_bp, 2)}#将列表a，b转换成字典
    reg = DataFrame(reg)

    rileijishouyi = {"date": meirishouyirq, "ret": meirileijishouyi}
    rileijishouyi = DataFrame(rileijishouyi)
    print('-----------------------------------------------------综合指标----------------------------------------------------')
    print(reg)
    return reg, rileijishouyi

if __name__ == '__main__':
    bcsj = int(datetime.datetime.now().strftime('%H%M%S%f'))
    # fun = func.BasicStatsOpe()
    np.set_printoptions(threshold=26, edgeitems=35, suppress=True)#设置np输出时显示的长度和宽度,和不用科学计数法显示
    # B = np.array([[4, 2, 3, 55], [5, 6, 37, 8], [-7, 68, 9, 0]])
    df = Return(Loddata('close_30m')[0:], 21)

    # print(df)
    # close = Loddata('close_30m')[0:]
    # print(np.shape(close))
    # df = -fun.Skew(close, 60)
    # df = fun.DECAY_LINEAR(df,60)
    # print(np.shape(df))
    # df = lod_data('close_HB1d')
    # print(len(df[:, 0]))
    nianshouyi, meirileijishouyi= HuiCe6(df, 30, 0) # 默认的输出每行元素的索引值。这些索引值对应的元素是从小到大排序的df[5000:, :]
    # print(meirileijishouyi)
    # meirileijishouyi.to_csv('每日累计收益60m.csv')
    print('运行耗时===', int(datetime.datetime.now().strftime('%H%M%S%f')) - bcsj)
    meirileijishouyi.plot()
    # nianshouyi.plot()
    # plt.plot(meirileijishouyi['date'], meirileijishouyi['shouyi'])#指定x轴和y轴要显示的列表
    # plt.title("meirileijishouyilv")
    plt.show()

    # pxhsj = pd.DataFrame(df)
    # pxhsj.to_csv('收益测试用')
    # shouyi = np.load('shouyi.npy', allow_pickle=True)
    # shouyizhibao(shouyi)
    # np.save('shouyi_HB5M', df)
    # shouyilv = Return(df, 1)
    # print(shouyilv)
    # shouyilv = shouyidian(df)
    # print(shouyilv)
    # np.save('60m\\shouyi_HB60m_nan.npy', df)
    # print(chengzhijisuan('RB888'))
    # print(sum(abs(pxhsj[len(pxhsj[:0])-1])),sum(abs(pxhsj[len(pxhsj[:0])-3])))
    #np.savetxt('featvector.csv',pxhsj,delimiter=',')
    #help(lod_data)
